home *** CD-ROM | disk | FTP | other *** search
/ Chip 1999 October / CHIP_CD_1999_10_PL.iso / offline / software / be / Be Book / The Interface Kit / demos / AlphaTransparencyDemo.cpp < prev   
Encoding:
C/C++ Source or Header  |  1999-06-05  |  12.9 KB  |  458 lines

  1. #include <AppKit.h>
  2. #include <InterfaceKit.h>
  3. #include <stdio.h>
  4. #include <math.h>
  5. #include <Message.h>
  6. #include <assert.h>
  7.  
  8. int dist(BPoint p1, BPoint p2) {
  9.     BPoint diff = p1-p2;
  10.     return (int)sqrt(diff.x*diff.x + diff.y*diff.y);
  11. }
  12.  
  13. /* A few consts to make the code easier to read */
  14. const int fully_opaque = 255;
  15. const int very_opaque = 230;
  16. const int three_fourths_opaque = 192;
  17. const int half_transparent = 128;
  18. const int three_fourths_transparent = 64;
  19. const int very_transparent = 25;
  20. const int fully_transparent = 0;
  21.  
  22. char *opacityToOpacityName(int op) {
  23.     if (op == fully_opaque) return "Fully opaque";
  24.     else if (op == very_opaque) return "Very opaque";
  25.     else if (op == three_fourths_opaque) return "75% opaque";
  26.     else if (op == half_transparent) return "50% transparent";
  27.     else if (op == three_fourths_transparent) return "75% transparent";
  28.     else if (op == very_transparent) return "Very transparent";
  29.     else if (op == fully_transparent) return "Fully transparent";
  30.     else return "???";
  31. }
  32.  
  33. rgb_color black = {0, 0, 0, 64};
  34. rgb_color white = {255, 255, 255, 0};
  35. rgb_color red = {255, 0, 0, 0};
  36. rgb_color green = {0, 255, 0, 0};
  37. rgb_color blue = {0, 0, 255, 0};
  38.  
  39. bool operator==(rgb_color c1, rgb_color c2) {
  40.     /* Ignore alpha component--just comparing colors */
  41.     if (c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue) {
  42.         return true; 
  43.     } else {
  44.         return false;
  45.     }
  46. }
  47.  
  48. char *colorToColorName(rgb_color c) {
  49.     if (c==black) return "Black";
  50.     else if (c==white) return "White";
  51.     else if (c==red) return "Red";
  52.     else if (c==green) return "Green";
  53.     else if (c==blue) return "Blue";
  54.     else return "???";
  55. }
  56.     
  57.  
  58. const char *APP_SIGNATURE = "application/x-vnd.Be-DrawingModesDemo";
  59.  
  60.  
  61.  
  62. /************* Class representing squares (the only thing we draw *************/
  63. class Square { 
  64.     public:
  65.         /* A square is defined by its size/location (first arg), drawing mode (second arg), alpha mode 
  66.             settings (3rd and 4th args--meaningful only if the drawing mode is B_OP_ALPHA), a color,
  67.             and an opacity (meaningful only if using a constant-source alpha drawing mode */
  68.         Square(BRect r, drawing_mode dm, source_alpha alpha1, alpha_function alpha2, rgb_color color, int opacity)
  69.         {
  70.             /* Squares are maintained in a linked list representing
  71.                 layerwise ordering. */
  72.             next = this;
  73.             prev = this;
  74.         
  75.             /* Squares drawn using the B_PIXEL_ALPHA setting will be drawn
  76.                 as a gradated bitmap, going from completely transparent on
  77.                 the left edge of the square to completely opaque on the 
  78.                 right edge. */
  79.             if (alpha1 == B_PIXEL_ALPHA) {
  80.                 int width = (int)(r.right - r.left);
  81.                 int height = (int)(r.bottom - r.top);
  82.                 /* Create a bitmap of appropriate size */
  83.                 BBitmap *square = new BBitmap(BRect(0, 0, width, height), B_RGB_32_BIT, true);
  84.                 BView* sview = new BView(BRect(0, 0, width, height), "", B_FOLLOW_ALL_SIDES, (uint32)NULL);
  85.                 square->AddChild(sview);
  86.                 square->Lock();
  87.                 /* Draw lines of varying transparency to create the gradated bitmap */
  88.                 for(int i = 0; i<=width; i++) {    
  89.                     color.alpha = (uint8)((float)i/width * 255);
  90.                     sview->SetHighColor(color);
  91.                     sview->StrokeLine(BPoint(i, 0), BPoint(i, height));
  92.                 }
  93.                 sview->Sync();
  94.                 square->RemoveChild(sview);
  95.                 square->Unlock();
  96.                 /* Save the bitmap so it can be drawn onscreen later */
  97.                 bitmap = square;
  98.             }
  99.  
  100.             /* For squares drawn using the B_CONSTANT_ALPHA setting, we
  101.                 will need to remember the opacity. */
  102.             color.alpha = opacity;
  103.             
  104.             rectangle = r;
  105.             AssignModes(dm, alpha1, alpha2, color);
  106.         }
  107.         
  108.         /* AssignModes() keeps the various drawing mode settings, so
  109.             we can set them in whatever view we draw to */
  110.         void AssignModes(drawing_mode drMode, source_alpha blend1, alpha_function blend2, rgb_color hi) {
  111.             blendmode1 = blend1;
  112.             blendmode2 = blend2;
  113.             hiColor = hi;
  114.             drawMode = drMode;
  115.         }
  116.         
  117.         /* Retrieves saved modes, and sets them on aView */
  118.         void UseModes(BView *aView) {
  119.             aView->SetDrawingMode(drawMode);
  120.             aView->SetBlendingMode(blendmode1, blendmode2);
  121.             aView->SetHighColor(hiColor);
  122.         }
  123.  
  124.         /* Insert d either after or before this square, in the
  125.             linked list of squares */
  126.         void Append(Square* d, bool before=false) {
  127.             if (before) { prev->Append(d); }
  128.             else {
  129.                 d->next = next;
  130.                 next->prev = d;
  131.                 d->prev = this;
  132.                 next = d;
  133.             }
  134.         }
  135.         
  136.         /* Remove this square from the linked list of squares */
  137.         void RemoveFromList() {
  138.             next->prev = prev;
  139.             prev->next = next;
  140.             prev = next = (Square*)NULL;
  141.         }
  142.     
  143.         BPoint location;
  144.         Square *next, *prev;
  145.         drawing_mode drawMode;
  146.         source_alpha blendmode1;
  147.         alpha_function blendmode2;
  148.         rgb_color hiColor;
  149.         rgb_color loColor;        
  150.         BRect rectangle;
  151.         BBitmap *bitmap;
  152.         
  153.         /* Draw a square into aView. If highlight is true, the square
  154.             should be highlighted with a thick border (used to indicate
  155.             it is the "topmost" square */
  156.         virtual void Draw(BView *aView, bool highlight) {
  157.             char *drawMode, *blendMode, *overlayMode, *drawSource = "";
  158.             blendMode = "";
  159.             overlayMode = "";
  160.             UseModes(aView);
  161.             source_alpha src;
  162.             switch (aView->DrawingMode()) {
  163.                 case B_OP_COPY : {
  164.                     drawMode = "COPY";
  165.                     break;
  166.                 }
  167.                 case B_OP_INVERT : {
  168.                     drawMode = "INVERT";
  169.                     break;
  170.                 }
  171.                 case B_OP_ALPHA : {
  172.                     alpha_function fnc;
  173.                     aView->GetBlendingMode(&src, &fnc);
  174.                     switch (src) {
  175.                         case B_CONSTANT_ALPHA : {
  176.                             drawSource = "B_CONSTANT_ALPHA";
  177.                             break;
  178.                         }
  179.                         case B_PIXEL_ALPHA : {
  180.                             drawSource = "B_PIXEL_ALPHA";
  181.                             break;
  182.                         }
  183.                         default : {
  184.                             drawSource = "???_alpha";
  185.                         }
  186.                     }
  187.                     switch (fnc) {
  188.                         case B_ALPHA_OVERLAY : {
  189.                             drawMode = "B_ALPHA_OVERLAY";
  190.                             break;
  191.                         }
  192.                         case B_ALPHA_COMPOSITE : {
  193.                             drawMode = "B_ALPHA_COMPOSITE";
  194.                             break;
  195.                         }
  196.                         default : {
  197.                             drawMode = "ALPHA_???";
  198.                             break;
  199.                         }
  200.                     }
  201.                     break;
  202.                 }
  203.                 default: {
  204.                     drawMode = "???";
  205.                     break;
  206.                 }
  207.             }
  208.             if (src == B_CONSTANT_ALPHA) {
  209.                 aView->FillRect(rectangle);
  210.             } else {
  211.                 aView->DrawBitmap(bitmap, rectangle);
  212.             }
  213.             rgb_color hi = aView->HighColor();
  214.             aView->SetDrawingMode(B_OP_COPY);
  215.             char *colorString = colorToColorName(aView->HighColor());
  216.             aView->SetHighColor(black);
  217.             if (highlight) {
  218.                 BRect r = BRect(rectangle);
  219.                 r.InsetBy(1, 1);
  220.                 int oldPenSize = (int)aView->PenSize();
  221.                 aView->SetPenSize(3);
  222.                 aView->StrokeRect(r);
  223.                 aView->SetPenSize(oldPenSize);
  224.             } else {
  225.                 aView->StrokeRect(rectangle);
  226.             }
  227.             /* Draw text in inverted mode so it shows up better */
  228.             aView->SetDrawingMode(B_OP_INVERT);
  229.             aView->MovePenTo(BPoint(rectangle.left + 5, rectangle.top + 15));
  230.             aView->DrawString("Color: ");
  231.             aView->DrawString(colorString);
  232.             aView->MovePenTo(BPoint(rectangle.left+5, rectangle.top+30));
  233.             aView->DrawString(drawMode);
  234.             aView->MovePenTo(BPoint(rectangle.left+5, rectangle.top+45));
  235.             aView->DrawString(drawSource);
  236.             aView->MovePenTo(BPoint(rectangle.left+5, rectangle.top+60));
  237.             if (src == B_CONSTANT_ALPHA) {
  238.                 aView->DrawString(opacityToOpacityName(hi.alpha));
  239.             } else {
  240.                 aView->DrawString("Variable opacity");
  241.             }
  242.             aView->SetDrawingMode(B_OP_COPY);
  243.         }        
  244.         
  245.         /* Returns true if the square contains p, false otherwise */
  246.         bool Contains(BPoint p) {
  247.             int t = (int)rectangle.top;
  248.             int b = (int)rectangle.bottom;
  249.             int l = (int)rectangle.left;
  250.             int r = (int)rectangle.right;
  251.             
  252.             return l <= p.x && p.x <= r && t <= p.y && p.y <= b;
  253.         }
  254.     
  255.     /* Returns true if the invoking square intersects the given BRect */
  256.     bool Intersects(BRect where) {
  257.         return rectangle.Intersects(where);
  258.     }
  259.  
  260. };
  261.  
  262. class AlphaView : public BView {
  263.     public:
  264.         AlphaView(BRect rect, char* name, uint32 sides, uint32 flags) 
  265.             : BView(rect, name, sides, flags) {
  266.             viewRect = rect;
  267.             assert(viewRect.top == 0 && viewRect.left == 0);
  268.             SetViewColor(B_TRANSPARENT_32_BIT);
  269.             /* Offscreen bitmap is used for double-buffering, so we
  270.                 can avoid flicker */
  271.             offscreenBitmap  = new BBitmap(rect, B_RGB_32_BIT, true);
  272.             offscreenView = new BView(rect, "", B_FOLLOW_NONE, (uint32)NULL);
  273.             offscreenBitmap->AddChild(offscreenView);
  274.             shapes = NULL;
  275.             MakeShapes();
  276.         }
  277.         
  278.         /* Create a bunch of shapes. */
  279.         void MakeShapes() {
  280.             rgb_color colors[] = {red, green, blue};
  281.             int numOfColors = 3;
  282.             int opacities[] = {fully_opaque, three_fourths_transparent, fully_transparent};
  283.             int numOfOpacities = 3;
  284.             int top, left;
  285.             top = 0;
  286.             shapes = NULL;
  287.             for (int nc=0; nc < numOfColors; nc++) {
  288.                 for (int oi=0; oi < numOfOpacities; oi++) {
  289.                     top = 20 + (nc * 160);
  290.                     left = 20 + (oi * 160);
  291.                     Square *sq = new Square(BRect(left, top, left+140, top+140), B_OP_ALPHA, B_CONSTANT_ALPHA, B_ALPHA_OVERLAY, colors[nc], opacities[oi]);
  292.                     
  293.                     if (shapes==NULL) {
  294.                         shapes = sq;
  295.                     } else {
  296.                         shapes->Append(sq);
  297.                     }
  298.                 }
  299.             }
  300.             top += 160;
  301.             for (int nc=0; nc < numOfColors; nc++) {
  302.                 left = 20 + (nc * 160);
  303.                 Square *sq = new Square(BRect(left, top, left+140, top+140 ), B_OP_ALPHA, B_PIXEL_ALPHA, B_ALPHA_OVERLAY, colors[nc], opacities[0]);
  304.                 shapes->Append(sq);
  305.             }
  306.         }
  307.         
  308.         Square* FindClickedOn(BPoint where) {
  309.             if (shapes == NULL) {
  310.                 return (Square*)NULL;
  311.             }
  312.             else {
  313.                 Square *current = shapes;
  314.                 while(1) {
  315.                     if (current->Contains(where)) {
  316.                         Invalidate(shapes->rectangle);
  317.                         return current;
  318.                     }
  319.                     else { current = current->next; }
  320.                     if (current == shapes) return (Square*)NULL;
  321.                 }
  322.             }
  323.         }
  324.         void MouseUp(BPoint where) {
  325.             dragging = (Square *)NULL;
  326.         }
  327.         
  328.         void MouseMoved(BPoint where, uint32 transit, const BMessage *message) {
  329.             if (dragging != NULL) {
  330.                 if ((where - lastMousePos) != BPoint(0,0)) {
  331.                     Invalidate(dragging->rectangle);
  332.                     dragging->location += (where - lastMousePos);
  333.                     dragging->rectangle.OffsetBy(where - lastMousePos);
  334.                     lastMousePos = where;
  335.                     Invalidate(dragging->rectangle);
  336.                     Window()->UpdateIfNeeded();
  337.                 }
  338.             }
  339.  
  340.         }
  341.         
  342.         void MouseDown(BPoint where) {
  343.             int32 buttons;
  344.             Window()->CurrentMessage()->FindInt32("buttons", &buttons);
  345.             if (buttons == B_PRIMARY_MOUSE_BUTTON) {
  346.                 lastMousePos = where;
  347.                 dragging = FindClickedOn(where);
  348.                 if (dragging != NULL && dragging != shapes) {
  349.                     dragging->RemoveFromList();
  350.                     shapes->Append(dragging, true);
  351.                     shapes = dragging;
  352.                     SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
  353.                 }
  354.             } else if (buttons == B_SECONDARY_MOUSE_BUTTON) {
  355.                 rgb_color c = GetPoint(where);
  356.                 printf("At pixel (%f, %f), R:%d, G:%d, B:%d, Alpha = %d\n", where.x, where.y, c.red, c.green, c.blue, c.alpha);
  357.             }
  358.         }
  359.         
  360.         /* Draw anything that needs to be drawn. */
  361.         void Draw(BRect where) {
  362.             Square *current;
  363.             offscreenBitmap->Lock();
  364.             offscreenView->SetLowColor(this->LowColor());
  365.             offscreenView->SetHighColor(this->LowColor());
  366.             offscreenView->FillRect(where);
  367.             Square *last = current = shapes->prev;
  368.             bool highlight = false;
  369.             /* Iterate over everything in "shapes" */
  370.             while(1) {
  371.                 /* If this is the topmost square, highlight it with a thick border */
  372.                 if (current->prev==last) { highlight = true; }
  373.                 /* Only draw a shape if it intersects "where", the invalidated rectangle */
  374.                 if (current->Intersects(where)) {
  375.                     /* Draw into the offscreen bitmap, to avoid flickering */
  376.                     current->Draw(offscreenView, highlight);
  377.                 }
  378.                 current = current->prev;
  379.                 /* If done all shapes, break out of the loop */
  380.                 if (current == last) { break; }
  381.             }
  382.             /* Draw the invalidated portion of the offscreen bitmap
  383.                 into the onscreen view */
  384.             offscreenView->Sync();
  385.             DrawBitmap(offscreenBitmap, where, where);
  386.             offscreenBitmap->Unlock();
  387.         }
  388.         
  389.         rgb_color GetPoint(BPoint where) {
  390.             int bytesPerRow = offscreenBitmap->BytesPerRow();
  391.             int width = (int)(viewRect.right - viewRect.left + 1);
  392.             assert(width * 4 == bytesPerRow);
  393.             int offset = (int)(where.y*width + where.x);
  394.             rgb_color c = ((rgb_color *)offscreenBitmap->Bits())[offset];
  395.             rgb_color c2;
  396.             c2.blue = c.red;
  397.             c2.green = c.green;
  398.             c2.red = c.blue;
  399.             c2.alpha = c.alpha;
  400.             return c2;
  401.         }
  402.             
  403.         BRect viewRect;
  404.         Square *shapes;
  405.         Square *dragging;
  406.         BPoint lastMousePos;
  407.         BBitmap *offscreenBitmap;
  408.         BView *offscreenView;
  409. };
  410.     
  411. class MyWindow : public BWindow {
  412.     public:
  413.         MyWindow(BRect frame)
  414.             : BWindow(frame, "TITLE", B_TITLED_WINDOW, B_NOT_ZOOMABLE) {
  415.             drawView = new AlphaView(this->Bounds(), NULL, B_FOLLOW_ALL_SIDES, B_WILL_DRAW);
  416.             AddChild(drawView);
  417.             Show();
  418.         }
  419.  
  420.         // QuitRequested causes clicks on the window's "close"
  421.         // button in the titlebar to quit the application. Without
  422.         // this, we'd have to kill the application manually.
  423.         bool QuitRequested() {
  424.             be_app->PostMessage(B_QUIT_REQUESTED);
  425.             return true;
  426.         }
  427.         
  428.         void MessageReceived(BMessage* msg) {
  429.             switch(msg->what) {
  430.                 default: {
  431.                     break;
  432.                 }
  433.             }
  434.         }
  435.         
  436.         private: 
  437.             AlphaView *drawView;
  438. };
  439.  
  440. class MyApp : public BApplication {
  441.     public:
  442.         MyApp() : BApplication(APP_SIGNATURE) {
  443.             BRect windowRect;
  444.             windowRect.Set(50,50,600,800);
  445.             MyWindow *w = new MyWindow(windowRect);
  446.             w->SetTitle("Alpha Transparency Demo");
  447.         }
  448.     private:
  449.         MyWindow *theWindow;
  450. };
  451.  
  452. int main(void) {
  453.     MyApp *theApp;
  454.     theApp = new(MyApp);
  455.     theApp->Run();
  456.     delete theApp;
  457. }
  458.